/*
  * Mirante Tecnologia
  * Copyright 2010, Mirante Informatica LTDA, 
  * and individual contributors as indicated by the @authors tag
  *
  * This is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as
  * published by the Free Software Foundation; either version 2.1 of
  * the License, or (at your option) any later version.
  *
  * This software is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this software; if not, write to the Free
  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
  */
package com.miranteinfo.seam.jsf.renderer.radio;

import java.io.IOException;
import java.util.List;

import javax.faces.component.UIComponent;
import javax.faces.component.ValueHolder;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.convert.Converter;
import javax.faces.model.SelectItem;
import javax.faces.model.SelectItemGroup;

import com.sun.faces.renderkit.RenderKitUtils;

/**
 * <B>ReadoRenderer</B> is a class that renders the current value of
 * <code>UISelectOne<code> or <code>UISelectMany<code> component as a list of
 * radio buttons
 * 
 * Utilizado para renderizacao customizada em forma de tabela.
 * veja o componente gridSupport.
 * 
 * @author lucas lins
 */
public class RadioRenderer extends com.sun.faces.renderkit.html_basic.RadioRenderer{

	private enum Layout{PAGE_DIRECTION,LINE_DIRECTION,TABLE};
	
	@Override
    public void encodeEnd(FacesContext context, UIComponent component)
          throws IOException {

        rendererParamsNotNull(context, component);

        if (!shouldEncode(component)) {
            return;
        }

        ResponseWriter writer = context.getResponseWriter();
        assert(writer != null);

        String alignStr;
        int columns = 1;
        int freeColumns = 0;
        Object borderObj;
        Layout layout = Layout.LINE_DIRECTION;
        boolean newLine = false;
        int border = 0;
        
        if (component.getAttributes().get("tableLayout") != null) {
        	layout = Layout.TABLE;
        	columns = new Integer(component.getAttributes().get("columns").toString());
        	
        }else if (null != (alignStr = (String) component.getAttributes().get("layout"))) {
        	if(alignStr.equalsIgnoreCase("pageDirection")){
        		layout = Layout.PAGE_DIRECTION;
        	}else if(alignStr.equalsIgnoreCase("table")){
        		layout = Layout.TABLE;
        	}
        }
        
        if (null != (borderObj = component.getAttributes().get("border"))) {
            border = (Integer) borderObj;
        }

        Converter converter = null;
        if(component instanceof ValueHolder) {
            converter = ((ValueHolder)component).getConverter();
        }

        renderBeginText(component, border, !layout.equals(Layout.LINE_DIRECTION), context, true);

        List<SelectItem> items = RenderKitUtils.getSelectItems(context, component);

        if (!items.isEmpty()) {
            int idx = -1;
            boolean haveToCloseTableLine = false;
            for (SelectItem curItem : items) {
                idx++;
                
                switch (layout) {
					case PAGE_DIRECTION:
						writePageDirectionItem(context, component, writer, converter, idx, curItem);
						break;
	
					case TABLE:
						if(freeColumns == 0){
							newLine = true;
							freeColumns = columns - 1;
						}else{
							newLine = false;
							freeColumns--;
						}
						haveToCloseTableLine = writeTableItem(context, component, writer, newLine, freeColumns == 0, converter, idx, curItem);
						break;
						
					default:
						writeLineDirectionItem(context, component, writer, converter, idx, curItem);
						break;
				}
                
            }
            
            if(layout.equals(Layout.TABLE) && haveToCloseTableLine){
            	writer.endElement("tr");
		    	writer.writeText("\n", component, null);
            }
            
        }

        renderEndText(component, !layout.equals(Layout.LINE_DIRECTION), context);

    }

	private void writeLineDirectionItem(FacesContext context, UIComponent component,
			ResponseWriter writer, Converter converter,
			int idx, SelectItem curItem) throws IOException {
		// If we come across a group of options, render them as a nested
		// table.
		if (curItem instanceof SelectItemGroup) {
		    // write out the label for the group.
		    if (curItem.getLabel() != null) {
		        writer.startElement("td", component);
		        writer.writeText(curItem.getLabel(), component, "label");
		        writer.endElement("td");
		    }
		    writer.startElement("td", component);
		    writer.writeText("\n", component, null);
		    renderBeginText(component, 0, false, context, false);
		    // render options of this group.
		    SelectItem[] itemsArray = ((SelectItemGroup) curItem).getSelectItems();
		    for (int i = 0; i < itemsArray.length; ++i) {
		        renderOption(context, component, converter, itemsArray[i], false, i);
		    }
		    renderEndText(component, false, context);
		    writer.endElement("td");
		} else {
		    renderOption(context, component, converter, curItem, false, idx);
		}
	}
	
	private void writePageDirectionItem(FacesContext context, UIComponent component,
			ResponseWriter writer, Converter converter,
			int idx, SelectItem curItem) throws IOException {
		// If we come across a group of options, render them as a nested
		// table.
		if (curItem instanceof SelectItemGroup) {
		    // write out the label for the group.
		    if (curItem.getLabel() != null) {
	            writer.startElement("tr", component);
		        writer.startElement("td", component);
		        writer.writeText(curItem.getLabel(), component, "label");
		        writer.endElement("td");
	            writer.endElement("tr");
		    }
	        writer.startElement("tr", component);
		    writer.startElement("td", component);
		    writer.writeText("\n", component, null);
		    renderBeginText(component, 0, true, context, false);
		    // render options of this group.
		    SelectItem[] itemsArray = ((SelectItemGroup) curItem).getSelectItems();
		    for (int i = 0; i < itemsArray.length; ++i) {
		        renderOption(context, component, converter, itemsArray[i], true, i);
		    }
		    renderEndText(component, true, context);
		    writer.endElement("td");
	        writer.endElement("tr");
	        writer.writeText("\n", component, null);
		} else {
		    renderOption(context, component, converter, curItem, true, idx);
		}
	}
	
	/**
	 * @return boolean, true if the table line is not closed
	 */
	private boolean writeTableItem(FacesContext context, UIComponent component,
			ResponseWriter writer, boolean newLine, boolean lastElement, Converter converter,
			int idx, SelectItem curItem) throws IOException {
		
		// If we come across a group of options, render them as a nested
		// table.
		if (curItem instanceof SelectItemGroup) {
		    // write out the label for the group.
			
			if(newLine){
				writer.startElement("tr", component);
			}

			writer.startElement("td", component);
			renderBeginText(component, 0, true, context, false);
			
		    if (curItem.getLabel() != null) {
	            writer.startElement("tr", component);
		        writer.startElement("td", component);
		        writer.writeText(curItem.getLabel(), component, "label");
		        writer.endElement("td");
	            writer.endElement("tr");
		    }
		    
	        writer.startElement("tr", component);
		    writer.startElement("td", component);
		    writer.writeText("\n", component, null);
		    renderBeginText(component, 0, true, context, false);
		    // render options of this group.
		    SelectItem[] itemsArray = ((SelectItemGroup) curItem).getSelectItems();
		    for (int i = 0; i < itemsArray.length; ++i) {
		        renderOption(context, component, converter, itemsArray[i], true, i);
		    }
		    renderEndText(component, true, context);
		    writer.endElement("td");
		    writer.endElement("tr");
		    
		    renderEndText(component, true, context);
		    writer.endElement("td");
		    
		    if(lastElement){
		    	writer.endElement("tr");
		    	writer.writeText("\n", component, null);
		    	return false;
			}
		    
		} else {
			
			if(newLine){
				writer.startElement("tr", component);
			}
			
		    renderOption(context, component, converter, curItem, false, idx);
		    
		    if(lastElement){
		    	writer.endElement("tr");
		    	writer.writeText("\n", component, null);
		    	return false;
			}
		}
		
		return true;
	}
	
	
	@Override
	protected void renderOption(FacesContext context, UIComponent component,
			Converter converter, SelectItem curItem,
			boolean newLine, int itemNumber)
		  	throws IOException {
		super.renderOption(context, component, converter, curItem, newLine, itemNumber);
	}
}
